/*
 * manejarDisco.c
 *
 *  Created on: 25/12/2011
 *      Author: utn_so
 */

#include "manejarDisco.h"
#include "threads_Semaphores.h"



ptrNodoCola agregarPDD(ptrNodoCola *ptrCabeza,ptrNodoCola *ptrTalon,char* valor,int sock,pthread_t hilo,int pista,int cabeza,int sector)
{
    ptrNodoCola ptrNue;
    //ptrLstLect auxInic=NULL;
    //ptrLstLect auxFin=NULL;
    ptrNue = malloc(sizeof(NodoCola));

    if (ptrNue!= NULL) {
    	ptrNue->idPlanif=malloc(strlen(valor)*sizeof(char));
        sprintf(ptrNue->idPlanif,"%s",valor);
        ptrNue->cantLect=0;
        ptrNue->socket=sock;
        ptrNue->completo=0;
        ptrNue->cabeza=cabeza;
        ptrNue->pista=pista;
        ptrNue->sector=sector;
        ptrNue->thrPlanif=hilo;
        ptrNue->pedDupInic=NULL;
        ptrNue->pedDupFin=NULL;
        ptrNue->sgte= NULL;

        /*printf("ingrese sector (-1 para terminar): ");
        scanf("%d", &pedido);
        while(pedido>-1){
        	agregarPed(&auxInic,&auxFin,pedido);
        	ptrNue->lecturaInic=auxInic;
        	ptrNue->lecturaFin=auxFin;
        	(ptrNue->cantLect)++;
        	printf("ingrese sector (-1 para terminar): ");
        	scanf("%d", &pedido);
        }
        imprimirLstPed(auxInic);*/

        if (vaciaPDD(*ptrCabeza)){
            *ptrCabeza=ptrNue;
		}
        else{
            (*ptrTalon)->sgte=ptrNue;
        }

        *ptrTalon=ptrNue;
    }
    else{
        printf("error en malloc()\n");
    }
    return ptrNue;

}

char* quitarPDD(ptrNodoCola *ptrCabeza,ptrNodoCola *ptrTalon)
{
    char* valor;
    ptrNodoCola ptrTemp;

    valor=malloc(strlen((*ptrCabeza)->idPlanif)*sizeof(char));
    memcpy(valor,(*ptrCabeza)->idPlanif,strlen((*ptrCabeza)->idPlanif));
    ptrTemp=*ptrCabeza;

    *ptrCabeza=(*ptrCabeza)->sgte;

    if (*ptrCabeza== NULL){
        *ptrTalon=NULL;
    }

    free(ptrTemp);

    return valor;

}

int vaciaPDD(ptrNodoCola ptrCabeza)
{
    return ptrCabeza == NULL;
}

int vaciaLect(ptrLstPed ptrCabeza)
{
    return ptrCabeza == NULL;
}

void imprimirLstPDD(ptrNodoCola ptrActual)
{

    if(ptrActual== NULL){
        printf("cola vacia\n");
	}
    else{
        printf("Los PPD conectados actualmente son:\n");

        while (ptrActual!= NULL){
        	printf("Id_Disco= %s; ",ptrActual->idPlanif);
        	ptrActual=ptrActual->sgte;
        }
        //printf("cola terminada\n");//tmp
    }
}

void imprimirLstPed(ptrLstPed ptrActual)
{
	//printf("aca imprime subcola\n");
	
	if(ptrActual== NULL){
        printf("cola vacia\n");
	}
    else{
        printf("los sectores a leer para el disco actual fueron:\n");

        while (ptrActual!= NULL){
        	printf("Id_Sector= %d; ",ptrActual->sector);
            ptrActual=ptrActual->sgte;
        }
        printf("cola terminada\n");//tmp
    }
}
pedido quitarPed(ptrLstPed *ptrCabeza,ptrLstPed *ptrTalon)
{
	//printf("aca saca de subcola\n");
	
	pedido valor;
    ptrLstPed ptrTemp;

    valor.sector=(*ptrCabeza)->sector;
    valor.tipoAcceso=(*ptrCabeza)->tipoAcceso;
    valor.sock=(*ptrCabeza)->sock;
    ptrTemp=*ptrCabeza;
    *ptrCabeza=(*ptrCabeza)->sgte;

    if (*ptrCabeza== NULL){
        *ptrTalon=NULL;
    }

    free(ptrTemp);

    return valor;
}
void agregarPed(ptrLstPed *ptrCabeza,ptrLstPed *ptrTalon,pedido sector)
{
	ptrLstPed ptrNue;
    ptrNue = malloc(sizeof(LstPed));

    if (ptrNue!= NULL) {
        ptrNue->sector=sector.sector;
        ptrNue->tipoAcceso=sector.tipoAcceso;
        memset(ptrNue->buffer,0,512);
        memcpy(ptrNue->buffer,sector.buffer,512);
        ptrNue->sector=sector.sock;

        ptrNue->sgte= NULL;
        
        if (vaciaLect(*ptrCabeza)){
            *ptrCabeza=ptrNue;
		}
        else{
            (*ptrTalon)->sgte=ptrNue;
        }

        *ptrTalon=ptrNue;
    }
    else{
        printf("error en malloc()\n");
    }
}

ptrNodoCola distribuirLect(ptrNodoCola ptr,int sector,int tipo)
{
	/* Descripcion: la idea era hacer una distribucion justa, significa que
	 * el sector q me llega del FS se lo entrego al PDD q tenga menos lecturas
	 * pendientes, ante igualdad de lecturas pendientes se ejecuta tipo FIFO
	 * según el orden de conexión de los discos.*/

	ptrNodoCola ptrAux=NULL,aux=NULL;
	pedido ped;
	ped.sector=sector;
	ped.tipoAcceso=tipo;
	memset(ped.buffer,0,512);
	if(tipo==1){
		int minimo=-1; //lo inicializo en -1 para q el primero q venga lo pise

		if(ptr== NULL){
			printf("cola vacia\n");
		}
		else{
			ptrAux=ptr;
			while (ptrAux!= NULL){
				if((minimo==-1 || ptrAux->cantLect<minimo) && ptrAux->completo){
					minimo=ptrAux->cantLect;
					aux=ptrAux;
				}
				ptrAux=ptrAux->sgte;
			}//while


			NIPC paquete;
			char* bufferNIPC2;
			char* mensaje;
			mensaje=malloc(512);
			memset(mensaje,0,512);
			memcpy(mensaje,&sector,sizeof(uint32_t));
			cargarEstructura(&paquete,2,mensaje);
			bufferNIPC2 = malloc(paquete.payloadLength + sizeof(uint8_t) + sizeof(uint16_t) );
			serializar_NIPC(paquete,bufferNIPC2);
			ped.sock=aux->socket;
			if(sectores[sector]==0){
				down(mutexSectsGlob);
				sectores[sector]=aux->socket;
				up(mutexSectsGlob);
			}
			/*down(mutexLect);
			agregarPed(&(aux->pedidosInic),&(aux->pedidosFin),ped);
			up(mutexLect);*/
			enviarNIPC(bufferNIPC2,paquete.payloadLength+3,aux->socket);
			memset(mensaje,0,512);
			free(paquete.mensaje);
			free(mensaje);
			free(bufferNIPC2);


			(aux->cantLect)++;
		}//else
	}
	if(tipo==2){
		int pedInic=0;
		int pedFin;
		aux=ptr;
		if(aux!=NULL){
			ped.sock=aux->socket;
			int i;
			for(i=0;i<cantDiscosComp;i++){
				if(aux->completo){
					char* mensaje;
					mensaje=malloc(512);
					memset(mensaje,0,512);
					if(i==cantDiscosComp-1){
						pedFin=(aux->pista*aux->sector)-1;
					}
					else{
						pedFin=(aux->pista*aux->sector)/cantDiscosComp;
					}
					sprintf(mensaje,"%d.%d",pedInic,pedFin);
					int j;
					down(mutexSectsGlob);
					for(j=pedInic;j<pedFin+1;j++){
						sectores[j]=aux->socket;
					}
					up(mutexSectsGlob);
					printf("El disco con ID=\"%s\" recibira para realizar la sincronizacion del disco entrante desde el pedido %d hasta el pedido %d.\n",aux->idPlanif,pedInic,pedFin);
					NIPC paquete;
					char* bufferNIPC2;
					memset(mensaje,0,512);
					sprintf(mensaje,"%d.%d",pedInic,pedFin);
					cargarEstructura(&paquete,2,mensaje);
					bufferNIPC2 = malloc(paquete.payloadLength + sizeof(uint8_t) + sizeof(uint16_t) );
					serializar_NIPC(paquete,bufferNIPC2);
					enviarNIPC(bufferNIPC2,paquete.payloadLength+3,aux->socket);
					memset(mensaje,0,512);
					free(paquete.mensaje);
					free(mensaje);
					free(bufferNIPC2);
					pedInic=pedFin+1;
					if(aux->sgte!=NULL){
						aux=aux->sgte;
					}
				}
			}
		}
	}
	return aux;
}

int duplicarDisco(ptrNodoCola discos,int sectores)
{
	int i=0;

	ptrNodoCola aux;
	//char buffer[1024];
	//while(i<sectores+1){
	aux=distribuirLect(discos,i,2);
		//i++;
		//int j;
		//for(j=0;j<200000;j++)printf("");
		//printf("sector= %d\n",i);
		//while(recibirDatosA(buffer,aux->socket)==1)
		//while(recv(aux->socket,buffer,519,MSG_WAITALL)<=0);
		//(aux->cantLect)--;
		//ultimo=buscarPDD(discos,ultimoDiscoConectado);
		/*NIPC paquete;
		char* bufferNIPC;
		char* mensaje;
		mensaje=malloc(512+sizeof(uint32_t));
		memset(mensaje,0,512+sizeof(uint32_t));
		memcpy(mensaje,buffer,512);
		memcpy(mensaje+512,&i,sizeof(uint32_t));
		cargarEstructura(&paquete,3,mensaje);
		bufferNIPC = malloc(sizeof(char)* paquete.payloadLength + sizeof(uint8_t) + sizeof(uint16_t) );
		serializar_NIPC(paquete,bufferNIPC);
		enviarNIPC(bufferNIPC,paquete.payloadLength+3,ultimo->socket);
		memset(mensaje,0,512+sizeof(uint32_t));
		free(paquete.mensaje);
		free(mensaje);
		free(bufferNIPC);
		while(recibirDatosA(buffer,ultimo->socket)==1);*/
	//}

	return 0;
}

ptrNodoCola buscarPDD(ptrNodoCola ptrCabeza,char* id)
{

	ptrNodoCola aux;
	aux=ptrCabeza;

	while(aux!=NULL && strcmp(aux->idPlanif,id)!=0){
		aux=aux->sgte;
	}

	return aux;
}

void frenarDiscos(ptrNodoCola discos)
{

	/* Deja q terminen los pedidos actuales de los discos y
	 * los detiene para poder sincronizar los cabezales.
	 */

	NIPC paquete;
	char* bufferNIPC3;
	char mensaje[50];

	memset(mensaje,0,50);
	sprintf(mensaje,"Detener procesamiento, escritura entrante.\n");
	cargarEstructura(&paquete,27,mensaje);
	bufferNIPC3 = malloc(sizeof(char)* paquete.payloadLength + sizeof(uint8_t) + sizeof(uint16_t) );
	serializar_NIPC(paquete,bufferNIPC3);
	ptrNodoCola aux=NULL;
	aux=discos;
	while(aux!=NULL){
		enviarNIPC(bufferNIPC3,paquete.payloadLength+3,aux->socket);
		aux=aux->sgte;
	}
	memset(mensaje,0,50);
	free(paquete.mensaje);
	free(bufferNIPC3);
}

void escribirEnDiscos(ptrNodoCola discos,int sector,char* buffer)
{
	frenarDiscos(discos);

	NIPC paquete;
	char* bufferNIPC4;
	char* mensaje;

	int tamMsj=512+sizeof(int);
	mensaje=malloc(tamMsj);
	memset(mensaje,0,tamMsj);
	memcpy(mensaje,buffer,512);
	memcpy(mensaje+512,&sector,sizeof(uint32_t));
	cargarEstructura(&paquete,2,mensaje);
	bufferNIPC4 = malloc(sizeof(char)* paquete.payloadLength + sizeof(uint8_t) + sizeof(uint16_t) );
	serializar_NIPC(paquete,bufferNIPC4);

	ptrNodoCola aux=NULL;
	aux=discos;
	while(aux!=NULL){
		enviarNIPC(bufferNIPC4,paquete.payloadLength+3,aux->socket);
		aux=aux->sgte;
	}
	memset(mensaje,0,tamMsj);
	free(paquete.mensaje);
	free(mensaje);
	free(bufferNIPC4);
	free(mensaje);
}

int buscarDiscoCompleto(ptrNodoCola discos)
{

	ptrNodoCola aux;
	aux=discos;
	while(aux!=NULL && !aux->completo){
		aux=aux->sgte;
	}

	if(aux==NULL){
		return 0;
	}
	return 1;
}

int buscarPed(ptrLstPed ptrCabeza,int sector)
{
	ptrLstPed aux;
	aux=ptrCabeza;

	while(aux!=NULL && aux->sector!=sector){
		aux=aux->sgte;
	}
	if(aux!=NULL){
		return 0;
	}
	else{
		return 1;
	}
}

ptrNodoCola buscarSock(ptrNodoCola ptrCabeza,int sock)
{
	ptrNodoCola aux;
	aux=ptrCabeza;

	while(aux!=NULL && aux->socket!=sock){
		aux=aux->sgte;
	}

	return aux;
}

int buscarParaEliminar(ptrNodoCola* lista,int sock)
{

	ptrNodoCola ptrAnterior;
	ptrNodoCola ptrActual;
	ptrNodoCola tempPtr;
		if((*lista)->socket == sock){
			tempPtr = *lista;
			*lista = (*lista)->sgte;
			printf("El disco con ID=\"%s\" fue eliminado del RAID.\n",tempPtr->idPlanif);
			if(tempPtr->completo){
				cantDiscosComp--;
			}
			free(tempPtr);
		}
		else{
			ptrAnterior = *lista;
			ptrActual = (*lista)->sgte;
			while(ptrActual != NULL && ptrActual->socket!=sock){
				ptrAnterior = ptrActual;
				ptrActual = ptrActual->sgte;
			}
			if(ptrActual != NULL){
				tempPtr = ptrActual;
				ptrAnterior->sgte = ptrActual->sgte;
				printf("El disco con ID=\"%s\" fue eliminado del RAID.\n",tempPtr->idPlanif);
				if(tempPtr->completo){
					cantDiscosComp--;
				}
				free(tempPtr);
			}
		}
	return 0;
}

ptrNodoCola agregarFS(ptrNodoCola *ptrCabeza,ptrNodoCola *ptrTalon,int sock,pthread_t hilo)
{
    ptrNodoCola ptrNue;
    ptrNue = malloc(sizeof(NodoCola));

    if (ptrNue!= NULL) {
    	ptrNue->socket=sock;
        ptrNue->thrPlanif=hilo;
        ptrNue->cabeza=-1;
        ptrNue->cantLect=-1;
        ptrNue->completo=-1;
        ptrNue->idPlanif=NULL;
        ptrNue->pista=-1;
        ptrNue->sector=-1;
        ptrNue->sgte= NULL;

        if (vaciaPDD(*ptrCabeza)){
            *ptrCabeza=ptrNue;
		}
        else{
            (*ptrTalon)->sgte=ptrNue;
        }

        *ptrTalon=ptrNue;
    }
    else{
        printf("error en malloc()\n");
    }
    return ptrNue;

}

void redistribuirPeds(int** pedidos,int socket,ptrNodoCola discos)
{
	int i;
	int inic=0,fin=0,flag=0;

	for(i=0;i<(pistaRaid*sectorRaid);i++){
		if(sectores[i]==socket){
			if(flag==0){
				inic=i;
				flag=1;
			}
			sectores[i]=-1;
		}
		else{
			if(i>=inic && flag==1){
				fin=i;
				distribuirBloque(discos,inic,fin);
				inic=0;
				fin=0;
				flag=0;
			}
		}
	}
	fin=i;
	distribuirBloque(discos,inic,fin);
}

ptrNodoCola distribuirBloque(ptrNodoCola discos,int inic,int fin)
{
	int pedInic=inic;
	int pedFin;
	int sock;
	ptrNodoCola aux=discos;
	if(aux!=NULL){
		sock=aux->socket;
		int i;
		for(i=0;i<cantDiscosComp;i++){
			if(aux->completo){
				NIPC paquete;
				char* bufferNIPC2;
				char* mensaje;
				mensaje=malloc(512);
				memset(mensaje,0,512);
				if(i==cantDiscosComp-1){
					pedFin=fin-1;
				}
				else{
					pedFin=(fin-inic)/cantDiscosComp;
				}
				sprintf(mensaje,"%d.%d",pedInic,pedFin);
				int j;
				down(mutexSectsGlob);
				for(j=pedInic;j<pedFin+1;j++){
					sectores[j]=aux->socket;
				}
				up(mutexSectsGlob);
				printf("El disco con ID=\"%s\" recibira para realizar la sincronizacion del disco entrante desde el sector %d hasta el sector %d.\n",aux->idPlanif,pedInic,pedFin);
				pedInic=pedFin+1;
				cargarEstructura(&paquete,2,mensaje);
				bufferNIPC2 = malloc(paquete.payloadLength + sizeof(uint8_t) + sizeof(uint16_t) );
				serializar_NIPC(paquete,bufferNIPC2);
				enviarNIPC(bufferNIPC2,paquete.payloadLength+3,aux->socket);
				memset(mensaje,0,512);
				free(paquete.mensaje);
				free(mensaje);
				free(bufferNIPC2);

				if(aux->sgte!=NULL){
					aux=aux->sgte;
				}
			}
		}
	}
	return aux;
}

ptrMsj agregarMsj(ptrMsj* ptrCabeza,ptrMsj* ptrTalon,char* msj,int sock)
{
	ptrMsj ptrNue;
	ptrNue = malloc(sizeof(NodoMsj));

	    if (ptrNue!= NULL) {
	    	ptrNue->mensaje=malloc(strlen(msj)*sizeof(char));
	    	strcpy(ptrNue->mensaje,msj);
	    	ptrNue->sock=sock;
	        ptrNue->sgte= NULL;

	        if (vaciaPDD(*ptrCabeza)){
	            *ptrCabeza=ptrNue;
			}
	        else{
	            (*ptrTalon)->sgte=ptrNue;
	        }

	        *ptrTalon=ptrNue;
	    }
	    else{
	        printf("error en malloc()\n");
	    }
	    return ptrNue;

}

parMsjSock  quitarMsj(ptrMsj *ptrCabeza,ptrMsj *ptrTalon)
{
	ptrMsj ptrTemp;
	parMsjSock par;
	par.msj=malloc(strlen((*ptrCabeza)->mensaje)*sizeof(char));
	strcpy(par.msj,(*ptrCabeza)->mensaje);
	par.sock=(*ptrCabeza)->sock;
	ptrTemp=*ptrCabeza;
    *ptrCabeza=(*ptrCabeza)->sgte;

    if (*ptrCabeza== NULL){
        *ptrTalon=NULL;
    }

    free(ptrTemp->mensaje);
    free(ptrTemp);

    return par;
}

void agregarPedDup(ptrLstPedDup *ptrCabeza,ptrLstPedDup *ptrTalon,char* buffer)
{
	ptrLstPedDup ptrNue;
    ptrNue = malloc(sizeof(LstPedDup));

    if(ptrNue!= NULL){

    	ptrNue->buffer=malloc(519);
    	memcpy(ptrNue->buffer,buffer,519);

        ptrNue->sgte= NULL;

        if (vaciaLect(*ptrCabeza)){
            *ptrCabeza=ptrNue;
		}
        else{
            (*ptrTalon)->sgte=ptrNue;
        }

        *ptrTalon=ptrNue;
    }
    else{
        printf("error en malloc()\n");
    }
}

char* quitarPedDup(ptrLstPedDup *ptrCabeza,ptrLstPedDup *ptrTalon)
{

	char valor[519];
    ptrLstPedDup ptrTemp;

    memcpy(valor,(*ptrCabeza)->buffer,519);
    ptrTemp=*ptrCabeza;
    *ptrCabeza=(*ptrCabeza)->sgte;

    if (*ptrCabeza== NULL){
        *ptrTalon=NULL;
    }

    free(ptrTemp->buffer);

    free(ptrTemp);

    return valor;
}

int tienePedidos(int* pedidos,int sock)
{
	int i=0;
	while(1){
		if(pedidos[i]==sock){
			return 0;
		}
		if(i>=pistaRaid*sectorRaid){
			return 1;
		}
		i++;
	}
}
